﻿#include "jlinktool.h"
#include "ui_jlinktool.h"

JlinkTool::JlinkTool(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::JlinkTool)
{
    ui->setupUi(this);

    getParamHandle();
    jlinkLibLoadHandle();

    burnFileTimer = new QTimer(this);
    burnFileTimer->stop();
    connect(burnFileTimer, SIGNAL(timeout()),this, SLOT(burnFileTimerHandle()));
}

JlinkTool::~JlinkTool()
{
    delete ui;
}

void JlinkTool::getParamHandle(void)
{
   QSettings param(JLINK_PARAMETER_SAVA_FILE, QSettings::IniFormat);

   ui->lineEditAddr->setText(param.value("burnAddress").toString());
   if(ui->lineEditAddr->text().isEmpty())
   {
       ui->lineEditAddr->setText(JLINK_DEFAULT_BURN_ADDR);
   }
   ui->lineEditFilePath->setText(param.value("firmwarPath").toString());
}

void JlinkTool::setParamHandle(void)
{
    QSettings param(JLINK_PARAMETER_SAVA_FILE, QSettings::IniFormat);

    param.setValue("burnAddress", ui->lineEditAddr->text());
    param.setValue("firmwarPath", ui->lineEditFilePath->text());
}

void JlinkTool::infoShowHandle(QString info)
{
    QString timestamp = QDateTime::currentDateTime().toString("[hh:mm:ss.zzz]==> ");
    ui->textBrowserLog->append(timestamp + info);
}

void JlinkTool::jlinkLibLoadHandle(void)
{
    jlinkLib = new QLibrary("JLinkARM.dll");
    if(jlinkLib->load())
    {
        infoShowHandle("加载JLinkARM.dll成功");
        jlinkOpenFuncPtr = (jlinkOpenFunc)jlinkLib->resolve("JLINKARM_Open");
        jlinkCloseFuncPtr = (jlinkCloseFunc)jlinkLib->resolve("JLINKARM_Close");
        jlinkIsOpenFuncPtr = (jlinkIsOpenFunc)jlinkLib->resolve("JLINKARM_IsOpen");
        jlinkTIFSelectFuncPtr = (jlinkTIFSelectFunc)jlinkLib->resolve("JLINKARM_TIF_Select");
        jlinkSetSpeedFuncPtr = (jlinkSetSpeedFunc)jlinkLib->resolve("JLINKARM_SetSpeed");
        jlinkGetSpeedFuncPtr = (jlinkGetSpeedFunc)jlinkLib->resolve("JLINKARM_GetSpeed");
        jlinkResetFuncPtr = (jlinkResetFunc)jlinkLib->resolve("JLINKARM_Reset");
        jlinkHaltFuncPtr = (jlinkHaltFunc)jlinkLib->resolve("JLINKARM_Halt");
        jlinkReadMemFuncPtr = (jlinkReadMemFunc)jlinkLib->resolve("JLINKARM_ReadMem");
        jlinkWriteMemFuncPtr = (jlinkWriteMemFunc)jlinkLib->resolve("JLINKARM_WriteMem");
        jlinkEraseChipFuncPtr = (jlinkEraseChipFunc)jlinkLib->resolve("JLINK_EraseChip");
        jlinkExecCommandFuncPtr = (jlinkExecCommandFunc)jlinkLib->resolve("JLINKARM_ExecCommand");
        jlinkGetDLLVersionFuncPtr = (jlinkGetDLLVersionFunc)jlinkLib->resolve("JLINKARM_GetDLLVersion");
        jlinkGetSNFuncPtr = (jlinkGetSNFunc)jlinkLib->resolve("JLINKARM_GetSN");
        jlinkGetIdFuncPtr = (jlinkGetIdFunc)jlinkLib->resolve("JLINKARM_GetId");
        jlinkConnectFuncPtr = (jlinkConnectFunc)jlinkLib->resolve("JLINKARM_Connect");
        jlinkIsConnectedFuncPtr = (jlinkIsConnectedFunc)jlinkLib->resolve("JLINKARM_IsConnected");
    }
    else
    {
        infoShowHandle("加载JLinkARM.dll失败。。。");
    }
}

bool JlinkTool::jlinkOpen(void)
{
    if(jlinkOpenFuncPtr)
    {
        return jlinkOpenFuncPtr();
    }
    return false;
}

void JlinkTool::jlinkClose(void)
{
    if(jlinkCloseFuncPtr)
    {
        jlinkCloseFuncPtr();
    }
}

bool JlinkTool::jlinkIsOpen(void)
{
    if(jlinkIsOpenFuncPtr)
    {
        return jlinkIsOpenFuncPtr();
    }
    return false;
}

unsigned int JlinkTool::jlinkTIFSelect(int type)
{
    if(jlinkTIFSelectFuncPtr)
    {
        return jlinkTIFSelectFuncPtr(type);
    }
    return false;
}

void JlinkTool::jlinkSetSpeed(unsigned int speed)
{
    if(jlinkSetSpeedFuncPtr)
    {
        jlinkSetSpeedFuncPtr(speed);
    }
}

unsigned int JlinkTool::jlinkGetSpeed(void)
{
    if(jlinkGetSpeedFuncPtr)
    {
        return jlinkGetSpeedFuncPtr();
    }
    return 0;
}

void JlinkTool::jlinkReset(void)
{
    if(jlinkResetFuncPtr)
    {
        jlinkResetFuncPtr();
    }
}

int JlinkTool::jlinkHalt(void)
{
    if(jlinkHaltFuncPtr)
    {
        return jlinkHaltFuncPtr();
    }
    return 0;
}

int JlinkTool::jlinkReadMem(unsigned int addr, int len, void *buf)
{
    if(jlinkReadMemFuncPtr)
    {
        return jlinkReadMemFuncPtr(addr, len, buf);
    }
    return 0;
}

int JlinkTool::jlinkWriteMem(unsigned int addr, int len, void *buf)
{
    if(jlinkWriteMemFuncPtr)
    {
        return jlinkWriteMemFuncPtr(addr, len, buf);
    }
    return 0;
}

int JlinkTool::jlinkEraseChip(void)
{
    if(jlinkEraseChipFuncPtr)
    {
        return jlinkEraseChipFuncPtr();
    }
    return 0;
}

bool JlinkTool::jlinkExecCommand(const char *cmd, int a, int b)
{
    if(jlinkExecCommandFuncPtr)
    {
        return jlinkExecCommandFuncPtr(cmd, a, b);
    }
    return false;
}

unsigned int JlinkTool::jlinkGetDLLVersion(void)
{
    if(jlinkGetDLLVersionFuncPtr)
    {
        return jlinkGetDLLVersionFuncPtr();
    }
    return 0;
}

unsigned int JlinkTool::jlinkGetSN(void)
{
    if(jlinkGetSNFuncPtr)
    {
        return jlinkGetSNFuncPtr();
    }
    return 0;
}

unsigned int JlinkTool::jlinkGetId(void)
{
    if(jlinkGetIdFuncPtr)
    {
        return jlinkGetIdFuncPtr();
    }
    return 0;
}

bool JlinkTool::jlinkConnect(void)
{
    if(jlinkConnectFuncPtr)
    {
        return jlinkConnectFuncPtr();
    }
    return false;
}

bool JlinkTool::jlinkIsConnected(void)
{
    if(jlinkIsConnectedFuncPtr)
    {
        return jlinkIsConnectedFuncPtr();
    }
    return false;
}


void JlinkTool::on_buttonSelectFW_clicked()
{
    QString fwFileName = QFileDialog::getOpenFileName(this, "Firmware file", QCoreApplication::applicationDirPath(), "fw file(*.bin)");
    ui->lineEditFilePath->setText(fwFileName);
    setParamHandle();
}

bool JlinkTool::jlinkConnectHandle(void)
{
    if(jlinkIsOpen())
    {
        infoShowHandle(tr("设备连接成功"));
        return true;
    }
    jlinkOpen();
    if(jlinkIsOpen())
    {
        jlinkExecCommand("device = STM32F407IG", 0, 0);
        jlinkTIFSelect(JLINKARM_TIF_SWD);
        jlinkSetSpeed(4000);
        jlinkConnect();
        if(jlinkIsConnected()){
            infoShowHandle(tr("设备连接成功"));
            return true;
        }else
        {
            infoShowHandle(tr("连接设备失败! 请检查设备连接..."));
        }
    }
    else
    {
        infoShowHandle(tr("连接设备失败! 请检查烧录器连接..."));
    }
    return false;
}

void JlinkTool::jlinkdisconnectHandle(void)
{
    jlinkClose();
    if(!jlinkIsOpen())
    {
        infoShowHandle(tr("断开设备成功!"));
    }
    else {
        infoShowHandle(tr("断开设备失败..."));
    }
}

QString JlinkTool::jlinkGetCpuIdHandle(void)
{
    unsigned char cpuId[12]={0};
    char cpuIdTemp[128]={0};
    jlinkReadMem(0x1FFF7A10, 12, cpuId);
    jlinkReadMem(0x1FFF7A10, 12, cpuId);
    sprintf(cpuIdTemp, "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X%02X",
            cpuId[3], cpuId[2], cpuId[1], cpuId[0],
            cpuId[7], cpuId[6], cpuId[5], cpuId[4],
            cpuId[11], cpuId[10], cpuId[9], cpuId[8]);
    return QString(cpuIdTemp);
}



void JlinkTool::on_buttonClearShow_clicked()
{
    ui->textBrowserLog->clear();
}

void JlinkTool::on_buttonGetID_clicked()
{
    if(jlinkConnectHandle())
    {
        infoShowHandle(tr("获取CPU ID中，请稍后..."));
        infoShowHandle(tr("获取CPU ID成功: ") + jlinkGetCpuIdHandle());
        jlinkdisconnectHandle();
    }
}

void JlinkTool::on_buttoEraseFlash_clicked()
{
    if(jlinkConnectHandle())
    {
        infoShowHandle(tr("擦除flash中，请稍后..."));
        jlinkEraseChip();
        infoShowHandle(tr("擦除flash成功!"));
        jlinkdisconnectHandle();
    }
}

void JlinkTool::burnFileTimerHandle(void)
{
    int burnPercent = 0;
    if(burnFileTimer)
    {
        burnFileTimer->stop();

        if(burnFileContent.isEmpty())
        {
            ui->progressBarBurn->setValue(100);
            jlinkdisconnectHandle();
            infoShowHandle(tr("烧录完成!"));
            return;
        }
        else
        {
            if(burnFileContent.size() > JLINK_BURN_CONTENT_SIZE)
            {
                jlinkWriteMem(burnAddr, JLINK_BURN_CONTENT_SIZE, burnFileContent.data());
                burnAddr += JLINK_BURN_CONTENT_SIZE;
                burnFileContent.remove(0, JLINK_BURN_CONTENT_SIZE);
            }
            else
            {
                jlinkWriteMem(burnAddr, burnFileContent.size(), burnFileContent.data());
                burnAddr += burnFileContent.size();
                burnFileContent.clear();
            }

            burnPercent = (burnFileSize - burnFileContent.size()) * 100 / burnFileSize;
            ui->progressBarBurn->setValue(burnPercent);
            burnFileTimer->start(JLINK_BURN_TIME_INTERVAL);
        }
    }
}

void JlinkTool::on_buttonBurn_clicked()
{
    bool burnAddrIsOk = false;
    QFile burnFile;

    burnFileSize = 0;
    burnFileContent.clear();

    if(ui->lineEditFilePath->text().isEmpty())
    {
        infoShowHandle(tr("请选择要烧录的固件!"));
        return;
    }

    if(jlinkConnectHandle())
    {
        burnAddr = ui->lineEditAddr->text().trimmed().toInt(&burnAddrIsOk, 16);
        if(!burnAddrIsOk)
        {
            infoShowHandle(tr("烧录起始地址格式有误，请正确输入地址..."));
            jlinkdisconnectHandle();
            return;
        }
        burnFile.setFileName(ui->lineEditFilePath->text());
        burnFile.open(QIODevice::ReadOnly);
        if(burnFile.isOpen())
        {
            burnFileContent = burnFile.readAll();
            burnFileSize = burnFileContent.size();
            burnFile.close();

            infoShowHandle(tr("开始烧录固件, 请稍后..."));

            burnFileTimer->start(JLINK_BURN_TIME_INTERVAL);
        }
        else
        {
            infoShowHandle(tr("烧录固件打开失败，请检查文件是否存在..."));
            jlinkdisconnectHandle();
        }
    }
}

void JlinkTool::on_lineEditAddr_textChanged(const QString &arg1)
{
    Q_UNUSED(arg1);
    setParamHandle();
}
